﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
using System.Xml;

namespace GPCodeConjurer
{
	public class Ellipse : Node, IRectangularNode
	{
		public Ellipse()
		{
			// Add grabhandles
			var rect = this.Rect;
			this.AddRectangularGrabHandles();
		}


		public Ellipse(RectangleF rectangle)
			: this()
		{
			this.Rectangle = rectangle;
		}

		public RectangleF Rectangle { get; set; }


		internal override Rectangle Rect
		{ 
			get
			{
				return new Rectangle(
					Convert.ToInt32(this.Rectangle.X),
					Convert.ToInt32(this.Rectangle.Y),
					Convert.ToInt32(this.Rectangle.Width),
					Convert.ToInt32(this.Rectangle.Height)
					);
			}
		}



		internal override void DrawPath(GraphicsPath gp)
		{
			gp.AddEllipse(this.Rectangle);
		}

		public override string CreateCode()
		{

			string c = string.Empty;
			if (this.StartFigure)
				c += Environment.NewLine + "\tgp.StartFigure();";
			c += string.Format(
				"\r\n\tgp.AddEllipse(new RectangleF({0}f, {1}f, {2}f, {3}f));",
				this.Rectangle.X,
				this.Rectangle.Y,
				this.Rectangle.Width,
				this.Rectangle.Height);
			if (this.CloseFigure)
				c += Environment.NewLine + "\tgp.CloseFigure();";
			return c;
		}

		internal override bool PointIsOnNode(Point pt)
		{
			using (GraphicsPath gp = new GraphicsPath())
			{
				Pen pen = new Pen(Color.Black, 10f);
				this.DrawPath(gp);
				gp.Widen(pen);
				pen.Dispose();
				return gp.IsVisible(pt);
			}
		}

		internal override void OnGrabHandleMove(HandleMovedEventArgs e)
		{
			var grabHandle = e.GrabHandle;
			var rect = this.Rect;
			var newRect = this.Rectangle;

			if (grabHandle.Key.Contains("N"))
			{
				newRect.Height = rect.Bottom - grabHandle.Location.Y;
				newRect.Y = grabHandle.Location.Y;
			}
			if (grabHandle.Key.Contains("S"))
			{
				newRect.Height = grabHandle.Location.Y - rect.Y;
			}
			if (grabHandle.Key.Contains("E"))
			{
				newRect.Width = grabHandle.Location.X - rect.X;
			}
			if (grabHandle.Key.Contains("W"))
			{
				newRect.Width = rect.Right - grabHandle.Location.X;
				newRect.X = grabHandle.Location.X;
			}


			// Check of inverted size and change movebehavior if needed.
			bool inverted = ((this.Rectangle.Width < 0 && this.Rectangle.Height > 0) || (this.Rectangle.Height < 0 && this.Rectangle.Width > 0));
			if (inverted)
			{
				this.GrabHandles["NE"].MoveBehavior = HandleMoveBehavior.NWSE;
				this.GrabHandles["NW"].MoveBehavior = HandleMoveBehavior.NESW;
				this.GrabHandles["SE"].MoveBehavior = HandleMoveBehavior.NESW;
				this.GrabHandles["SW"].MoveBehavior = HandleMoveBehavior.NWSE;
			}
			else
			{
				this.GrabHandles["NE"].MoveBehavior = HandleMoveBehavior.NESW;
				this.GrabHandles["NW"].MoveBehavior = HandleMoveBehavior.NWSE;
				this.GrabHandles["SE"].MoveBehavior = HandleMoveBehavior.NWSE;
				this.GrabHandles["SW"].MoveBehavior = HandleMoveBehavior.NESW;
			}

			this.Rectangle = newRect.Absolute();
			this.RelocateGrabHandles();
		}

		internal override void OnMoved(NodeMovedEventArgs e)
		{
			this.Rectangle = new RectangleF(
				this.Rectangle.Location.X + e.Difference.Width,
				this.Rectangle.Location.Y + e.Difference.Height,
				this.Rectangle.Width,
				this.Rectangle.Height);

			// move the handles also
			foreach (var kvp in this.GrabHandles)
			{
				kvp.Value.Location = new Point(kvp.Value.Location.X + e.Difference.Width, kvp.Value.Location.Y + e.Difference.Height);
			}
		}


		internal override void RelocateGrabHandles()
		{
			var newRect = this.Rectangle;
			this.GrabHandles["NW"].Location = newRect.Location.ToPoint();
			this.GrabHandles["N"].Location = new PointF(newRect.Left + newRect.Width / 2, newRect.Top).ToPoint();
			this.GrabHandles["NE"].Location = new PointF(newRect.Right, newRect.Top).ToPoint();
			this.GrabHandles["W"].Location = new PointF(newRect.Left, newRect.Top + newRect.Height / 2).ToPoint();
			this.GrabHandles["E"].Location = new PointF(newRect.Right, newRect.Top + newRect.Height / 2).ToPoint();
			this.GrabHandles["SW"].Location = new PointF(newRect.Left, newRect.Bottom).ToPoint();
			this.GrabHandles["S"].Location = new PointF(newRect.Left + newRect.Width / 2, newRect.Bottom).ToPoint();
			this.GrabHandles["SE"].Location = new PointF(newRect.Right, newRect.Bottom).ToPoint();
		}


		public override object Clone()
		{
			Ellipse n = new Ellipse(this.Rectangle);
			return n;
		}


		public override XmlElement Serialize(XmlDocument xmlDoc)
		{
			var n = xmlDoc.CreateElement("Ellipse");
			this.SeralizeStartCloseFigure(n);
			n.AppendChild(this.Rectangle.Serialize(xmlDoc));
			return n;
		}

		public override void Deserialize(XmlElement seralizedElement)
		{
			this.DeseralizeStartCloseFigure(seralizedElement);
			this.Rectangle = ExtensionHelpers.DeserializeRectangleF(seralizedElement.SelectSingleNode("RectangleF") as XmlElement);
		}



		public override string ToString()
		{
			return "Ellipse";
		}

	}
}
